/*
 * lognumber.h
 *
 *  Created on: Mar 9, 2011
 *      Author: tqlong
 */

#ifndef LOGNUMBER_H_
#define LOGNUMBER_H_

#include <iostream>
#include <cmath>
#include <cassert>

class lognum
{
  double log_;
  double sign_;

  static double logsum(double loga, double logb);
  static double DOUBLE_INFINITY;
  static double TOLERANCE;
public:
  lognum(double d, double sign);  // log constructor
  lognum(double d = 0.0);         // double constructor
//  operator double() { std::cerr << "double conversion\n"; return ::exp(log_)*sign_; }

  lognum& operator=(double d);
  double toDouble() const { return sign_*::exp(log_); }

  double log() const { return log_; }
  double sgn() const { return sign_; }
  bool operator <  (const lognum& x) const;
  bool operator <= (const lognum& x) const;
  bool operator >  (const lognum& x) const;
  bool operator >= (const lognum& x) const;
  bool operator != (const lognum& x) const;
  bool operator == (const lognum& x) const;

  lognum  operator +  (const lognum& x) const { lognum tmp(*this); tmp += x; return tmp; }
  lognum  operator -  () const { lognum x(*this); x.sign_ = -sign_; return x; }
  lognum  operator -  (const lognum& x) const { return *this + (-x); }
  lognum  operator *  (const lognum& x) const { lognum tmp(*this); tmp *= x; return tmp; }
  lognum  operator /  (const lognum& x) const { lognum tmp(*this); tmp /= x; return tmp; }
  lognum& operator += (const lognum& x);
  lognum& operator -= (const lognum& x) { return operator+=(-x); }
  lognum& operator *= (const lognum& x) { sign_ *= x.sign_; log_ += x.log_; return *this; }
  lognum& operator /= (const lognum& x) { assert(x.log_ != DOUBLE_INFINITY); sign_ /= x.sign_; log_ -= x.log_; return *this; }
};

std::ostream& operator<<(std::ostream& s, const lognum& x);

namespace std {
  lognum log(const lognum& x);
  lognum sqrt(const lognum& x);
  lognum log1p(const lognum& x);
  lognum logistic(const lognum& x);
}

lognum operator + (double d, const lognum& x);
lognum operator - (double d, const lognum& x);
lognum operator * (double d, const lognum& x);
lognum operator / (double d, const lognum& x);

#endif /* LOGNUMBER_H_ */
